package com.zhaowt.service.impl;

import com.github.pagehelper.PageInfo;
import com.zhaowt.Enums.LoginResult;
import com.zhaowt.dto.UserDto;
import com.zhaowt.event.MyLoginEvent;
import com.zhaowt.exception.AddDataErrorException;
import com.zhaowt.exception.MyBaseException;
import com.zhaowt.exception.MyErrorCode;
import com.zhaowt.mapper.SysUserInfoMapper;
import com.zhaowt.pojo.SysUserInfo;
import com.zhaowt.service.SysUserInfoService;
import com.zhaowt.util.MD5Utils;
import com.zhaowt.util.MyStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 * created by 赵文韬 on 2022/12/14 16:48
 */
@Transactional
@Service
public class SysUserInfoServiceImpl implements SysUserInfoService {
    private ApplicationContext applicationContext;
    @Autowired
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Resource
    private SysUserInfoMapper sysUserInfoMapper;
    @Override
    public SysUserInfo findById(Long id) {
        return sysUserInfoMapper.findById(id);
    }

    @Override
    public PageInfo<SysUserInfo> findAll(int pageSize, int pageNum) {
        List<SysUserInfo> userInfos = sysUserInfoMapper.findAll();
        PageInfo<SysUserInfo> sysUserInfoPageInfo = new PageInfo<>(userInfos);
        return sysUserInfoPageInfo;
    }

    @Override
    public void addUser(SysUserInfo sysUserInfo) {
        Assert.isTrue(sysUserInfo.getSex()==0 || sysUserInfo.getSex()==1, ()->{
            throw  new MyBaseException("性别格式有误",MyErrorCode.SEX_ERROR );
        });
        //非空校验
        Assert.isTrue(!sysUserInfo.isEmpty(), ()->{
            throw new AddDataErrorException("数据为空",MyErrorCode.DATA_NULL );
        });
        //数据唯一性校验
        SysUserInfo byUserName = sysUserInfoMapper.findByUserName(sysUserInfo.getUsername());
        Assert.isNull(byUserName, ()->{
            throw new MyBaseException("用户名被占用",MyErrorCode.USER_ALREADY_EXIST);
        });
        Assert.isNull(sysUserInfoMapper.findByPhone(sysUserInfo.getPhone()), ()->{
            throw new MyBaseException("手机号被占用",MyErrorCode.PHONE_ALREADY_EXIST );
        });
        Assert.isNull(sysUserInfoMapper.findByEmail(sysUserInfo.getEmail()), ()->{
            throw new MyBaseException("邮箱号被占用",MyErrorCode.EMAIL_ALREADY_EXIST );
        });
        //数据格式校验
        Assert.isTrue(MyStringUtils.check(sysUserInfo.getEmail(), MyStringUtils.emaiRegex), ()->{
            throw new MyBaseException("邮箱格式不正确",MyErrorCode.MAIL_REG_NOT_MACTH );
        });
        Assert.isTrue(MyStringUtils.check(sysUserInfo.getPhone(), MyStringUtils.mobileRegex), ()->{
            throw new MyBaseException("电话号码格式不正确",MyErrorCode.PHONE_REG_NOT_MACTH );
        });

        //生成盐
        String salt = MD5Utils.getRandomString(10);
        sysUserInfo.setPwdSalt(salt);
        //生成密码
        String passwordMd5 = MD5Utils.getMd5(sysUserInfo.getPassword(), salt, 1024);
        sysUserInfo.setPassword(passwordMd5);
        //设置默认的数据
        sysUserInfo.setCreateTime(new Date());
        //检查当前登录的用户,如果是管理员,设置管理员的信息,如果没有用户就是用户自己注册的
        sysUserInfo.setCreateBy(sysUserInfo.getUsername());
        sysUserInfo.setRemark("普通用户");
        sysUserInfo.setCreateBy(sysUserInfo.getUsername());


        sysUserInfoMapper.addUser(sysUserInfo);
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    @Override
    public void login(UserDto userDto) {
        //用户名和密码的非空校验
        Assert.notNull(StringUtils.hasText(userDto.getUsername())&&StringUtils.hasText(userDto.getPassword()), ()->{
            throw new MyBaseException("用户名和密码不能为空",MyErrorCode.DATA_NULL );
        });
        //todo登录成功与失败都要记录日志，日志有专门的数据库表可以存储.
        //todosysUserInfoMapperByUserName中的用户名和密码置空，防止泄露到前端
        SysUserInfo sysUserInfoMapperByUserName = sysUserInfoMapper.findByUserName(userDto.getUsername());
        Assert.notNull(sysUserInfoMapperByUserName,()->{
            throw new MyBaseException("用户名或密码错误", MyErrorCode.USERNAME_PASSWORD_ERROR);
        } );
        String userNamePassword = sysUserInfoMapperByUserName.getPassword();
        String md5 = MD5Utils.getMd5(userDto.getPassword(), sysUserInfoMapperByUserName.getPwdSalt(), 1024);
        //equalsIgnoreCase()忽略大小写的字符串比较方法
        Assert.isTrue(md5.equalsIgnoreCase(userNamePassword), ()->{
            //记录失败日志
            applicationContext.publishEvent(new MyLoginEvent(LoginResult.FAIL,userDto.getUsername()));
            throw new MyBaseException("用户名或密码错误", MyErrorCode.USERNAME_PASSWORD_ERROR);
        });
        //记录成功日志
        applicationContext.publishEvent(new MyLoginEvent(LoginResult.SUCCESS,userDto.getUsername()));
        //置空用户名和密码，防止泄露
        sysUserInfoMapperByUserName.setPassword(null);
        sysUserInfoMapperByUserName.setUsername(null);
    }
}
